import sys
import os
import cv2
import numpy as np
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
                             QLabel, QPushButton, QFileDialog, QSlider, QComboBox, QGroupBox,
                             QSpinBox, QDoubleSpinBox, QTabWidget, QMessageBox, QAction, QMenu,
                             QSplitter, QProgressBar, QDockWidget, QTextEdit)  # 添加 QTextEdit 导入
from PyQt5.QtGui import QImage, QPixmap, QPainter, QPen, QColor
from PyQt5.QtCore import Qt, QTimer, QPoint, QRect

# 加载人脸检测器
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')


class CVPlatform(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

        # 初始化变量
        self.image = None
        self.original_image = None
        self.processed_image = None
        self.video_capture = None
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update_frame)
        self.is_video_playing = False
        self.shape_color = QColor(0, 255, 0)  # 形状识别默认颜色（绿色）

        # 连接信号与槽
        self.connect_signals()

    def initUI(self):
        # 设置窗口标题和大小
        self.setWindowTitle('计算机视觉开发平台')
        self.setGeometry(100, 100, 1200, 800)

        # 创建菜单栏
        self.create_menu_bar()

        # 创建工具栏
        self.create_tool_bar()

        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)

        # 创建主布局
        main_layout = QHBoxLayout(central_widget)

        # 创建分割器
        splitter = QSplitter(Qt.Horizontal)

        # 创建左侧面板（操作面板）
        left_panel = QWidget()
        left_layout = QVBoxLayout(left_panel)

        # 创建图像处理选项卡
        self.processing_tabs = QTabWidget()

        # 图像加载与显示选项卡
        self.load_display_tab = QWidget()
        load_display_layout = QVBoxLayout(self.load_display_tab)

        load_group = QGroupBox("图像加载")
        load_layout = QVBoxLayout(load_group)

        self.load_image_btn = QPushButton("加载图像")
        self.save_image_btn = QPushButton("保存图像")
        self.reset_image_btn = QPushButton("重置图像")

        load_layout.addWidget(self.load_image_btn)
        load_layout.addWidget(self.save_image_btn)
        load_layout.addWidget(self.reset_image_btn)

        display_group = QGroupBox("显示设置")
        display_layout = QVBoxLayout(display_group)

        self.zoom_in_btn = QPushButton("放大")
        self.zoom_out_btn = QPushButton("缩小")
        self.fit_to_screen_btn = QPushButton("适应屏幕")

        display_layout.addWidget(self.zoom_in_btn)
        display_layout.addWidget(self.zoom_out_btn)
        display_layout.addWidget(self.fit_to_screen_btn)

        load_display_layout.addWidget(load_group)
        load_display_layout.addWidget(display_group)
        load_display_layout.addStretch()

        # 图像编辑选项卡
        self.edit_tab = QWidget()
        edit_layout = QVBoxLayout(self.edit_tab)

        rotation_group = QGroupBox("旋转")
        rotation_layout = QVBoxLayout(rotation_group)

        self.rotation_angle_spin = QSpinBox()
        self.rotation_angle_spin.setRange(0, 359)
        self.rotation_angle_spin.setValue(0)
        self.rotate_btn = QPushButton("旋转")

        rotation_layout.addWidget(QLabel("旋转角度:"))
        rotation_layout.addWidget(self.rotation_angle_spin)
        rotation_layout.addWidget(self.rotate_btn)

        scaling_group = QGroupBox("缩放")
        scaling_layout = QVBoxLayout(scaling_group)

        self.scale_factor_spin = QDoubleSpinBox()
        self.scale_factor_spin.setRange(0.1, 10.0)
        self.scale_factor_spin.setValue(1.0)
        self.scale_factor_spin.setSingleStep(0.1)
        self.scale_btn = QPushButton("缩放")

        scaling_layout.addWidget(QLabel("缩放比例:"))
        scaling_layout.addWidget(self.scale_factor_spin)
        scaling_layout.addWidget(self.scale_btn)

        cropping_group = QGroupBox("裁剪")
        cropping_layout = QVBoxLayout(cropping_group)

        self.start_crop_btn = QPushButton("开始裁剪")
        self.apply_crop_btn = QPushButton("应用裁剪")
        self.apply_crop_btn.setEnabled(False)

        cropping_layout.addWidget(self.start_crop_btn)
        cropping_layout.addWidget(self.apply_crop_btn)

        edit_layout.addWidget(rotation_group)
        edit_layout.addWidget(scaling_group)
        edit_layout.addWidget(cropping_group)
        edit_layout.addStretch()

        # 图像色彩调整选项卡
        self.color_tab = QWidget()
        color_layout = QVBoxLayout(self.color_tab)

        brightness_group = QGroupBox("亮度")
        brightness_layout = QVBoxLayout(brightness_group)

        self.brightness_slider = QSlider(Qt.Horizontal)
        self.brightness_slider.setRange(-100, 100)
        self.brightness_slider.setValue(0)
        self.brightness_value_label = QLabel("亮度: 0")

        brightness_layout.addWidget(self.brightness_value_label)
        brightness_layout.addWidget(self.brightness_slider)

        contrast_group = QGroupBox("对比度")
        contrast_layout = QVBoxLayout(contrast_group)

        self.contrast_slider = QSlider(Qt.Horizontal)
        self.contrast_slider.setRange(-100, 100)
        self.contrast_slider.setValue(0)
        self.contrast_value_label = QLabel("对比度: 0")

        contrast_layout.addWidget(self.contrast_value_label)
        contrast_layout.addWidget(self.contrast_slider)

        saturation_group = QGroupBox("饱和度")
        saturation_layout = QVBoxLayout(saturation_group)

        self.saturation_slider = QSlider(Qt.Horizontal)
        self.saturation_slider.setRange(-100, 100)
        self.saturation_slider.setValue(0)
        self.saturation_value_label = QLabel("饱和度: 0")

        saturation_layout.addWidget(self.saturation_value_label)
        saturation_layout.addWidget(self.saturation_slider)

        self.apply_color_btn = QPushButton("应用色彩调整")

        color_layout.addWidget(brightness_group)
        color_layout.addWidget(contrast_group)
        color_layout.addWidget(saturation_group)
        color_layout.addWidget(self.apply_color_btn)
        color_layout.addStretch()

        # 图像平滑处理选项卡
        self.smoothing_tab = QWidget()
        smoothing_layout = QVBoxLayout(self.smoothing_tab)

        self.smoothing_algorithm_combo = QComboBox()
        self.smoothing_algorithm_combo.addItems(["均值滤波", "高斯滤波", "中值滤波", "双边滤波"])

        self.kernel_size_spin = QSpinBox()
        self.kernel_size_spin.setRange(1, 21)
        self.kernel_size_spin.setValue(3)
        self.kernel_size_spin.setSingleStep(2)

        self.apply_smoothing_btn = QPushButton("应用平滑处理")

        smoothing_layout.addWidget(QLabel("平滑算法:"))
        smoothing_layout.addWidget(self.smoothing_algorithm_combo)
        smoothing_layout.addWidget(QLabel("内核大小:"))
        smoothing_layout.addWidget(self.kernel_size_spin)
        smoothing_layout.addWidget(self.apply_smoothing_btn)
        smoothing_layout.addStretch()

        # 形状识别选项卡
        self.shape_tab = QWidget()
        shape_layout = QVBoxLayout(self.shape_tab)

        self.shape_type_combo = QComboBox()
        self.shape_type_combo.addItems(["所有形状", "圆形", "矩形", "三角形", "多边形"])

        self.detect_shapes_btn = QPushButton("检测形状")

        shape_layout.addWidget(QLabel("形状类型:"))
        shape_layout.addWidget(self.shape_type_combo)
        shape_layout.addWidget(self.detect_shapes_btn)
        shape_layout.addStretch()

        # 图像拼接选项卡
        self.stitch_tab = QWidget()
        stitch_layout = QVBoxLayout(self.stitch_tab)

        self.add_image_for_stitch_btn = QPushButton("添加图像")
        self.stitch_images_btn = QPushButton("拼接图像")

        self.stitch_images_list = []
        self.stitch_images_display = QLabel("已添加图像: 0")

        stitch_layout.addWidget(self.add_image_for_stitch_btn)
        stitch_layout.addWidget(self.stitch_images_display)
        stitch_layout.addWidget(self.stitch_images_btn)
        stitch_layout.addStretch()

        # 人脸识别选项卡
        self.face_tab = QWidget()
        face_layout = QVBoxLayout(self.face_tab)

        face_detection_group = QGroupBox("人脸检测")
        face_detection_layout = QVBoxLayout(face_detection_group)

        self.detect_faces_btn = QPushButton("检测人脸")
        # 移除人脸识别按钮（因缺少face_recognition模块）
        # self.recognize_faces_btn = QPushButton("识别已注册人脸")

        face_detection_layout.addWidget(self.detect_faces_btn)
        # face_detection_layout.addWidget(self.recognize_faces_btn)

        # 移除人脸注册功能
        face_registration_group = QGroupBox("人脸注册（需要face_recognition库）")
        face_registration_layout = QVBoxLayout(face_registration_group)

        self.register_info_label = QLabel("此功能需要安装face_recognition库\n"
                                        "请使用命令: pip install face_recognition")
        face_registration_layout.addWidget(self.register_info_label)

        face_layout.addWidget(face_detection_group)
        face_layout.addWidget(face_registration_group)
        face_layout.addStretch()

        # 视频处理选项卡
        self.video_tab = QWidget()
        video_layout = QVBoxLayout(self.video_tab)

        video_file_group = QGroupBox("视频文件")
        video_file_layout = QVBoxLayout(video_file_group)

        self.load_video_btn = QPushButton("加载视频")
        self.play_video_btn = QPushButton("播放")
        self.pause_video_btn = QPushButton("暂停")
        self.stop_video_btn = QPushButton("停止")
        self.next_frame_btn = QPushButton("下一帧")
        self.prev_frame_btn = QPushButton("上一帧")

        video_file_layout.addWidget(self.load_video_btn)
        video_file_layout.addWidget(self.play_video_btn)
        video_file_layout.addWidget(self.pause_video_btn)
        video_file_layout.addWidget(self.stop_video_btn)
        video_file_layout.addWidget(self.next_frame_btn)
        video_file_layout.addWidget(self.prev_frame_btn)

        webcam_group = QGroupBox("摄像头")
        webcam_layout = QVBoxLayout(webcam_group)

        self.start_webcam_btn = QPushButton("启动摄像头")
        self.stop_webcam_btn = QPushButton("停止摄像头")
        self.apply_cv_to_webcam_btn = QPushButton("应用计算机视觉")

        webcam_layout.addWidget(self.start_webcam_btn)
        webcam_layout.addWidget(self.stop_webcam_btn)
        webcam_layout.addWidget(self.apply_cv_to_webcam_btn)

        self.video_progress = QProgressBar()
        self.video_progress.setValue(0)

        video_layout.addWidget(video_file_group)
        video_layout.addWidget(webcam_group)
        video_layout.addWidget(self.video_progress)
        video_layout.addStretch()

        # 添加选项卡到选项卡控件
        self.processing_tabs.addTab(self.load_display_tab, "加载与显示")
        self.processing_tabs.addTab(self.edit_tab, "图像编辑")
        self.processing_tabs.addTab(self.color_tab, "色彩调整")
        self.processing_tabs.addTab(self.smoothing_tab, "平滑处理")
        self.processing_tabs.addTab(self.shape_tab, "形状识别")
        self.processing_tabs.addTab(self.stitch_tab, "图像拼接")
        self.processing_tabs.addTab(self.face_tab, "人脸识别")
        self.processing_tabs.addTab(self.video_tab, "视频处理")

        left_layout.addWidget(self.processing_tabs)

        # 将左侧面板添加到分割器
        splitter.addWidget(left_panel)

        # 创建右侧面板（显示区域）
        right_panel = QWidget()
        right_layout = QVBoxLayout(right_panel)

        # 创建图像/视频显示区域
        self.display_area = QLabel("请加载图像或视频")
        self.display_area.setAlignment(Qt.AlignCenter)
        self.display_area.setMinimumSize(400, 400)
        self.display_area.setStyleSheet("border: 1px solid #cccccc;")
        self.display_area.setScaledContents(True)

        # 创建结果显示区域
        self.results_area = QTextEdit()  # 使用已导入的 QTextEdit
        self.results_area.setReadOnly(True)
        self.results_area.setPlaceholderText("处理结果将显示在这里...")

        right_layout.addWidget(self.display_area)
        right_layout.addWidget(QLabel("处理结果:"))
        right_layout.addWidget(self.results_area)

        # 将右侧面板添加到分割器
        splitter.addWidget(right_panel)

        # 设置分割器的初始大小
        splitter.setSizes([300, 900])

        # 将分割器添加到主布局
        main_layout.addWidget(splitter)

        # 创建状态栏
        self.statusBar().showMessage('就绪')

        # 裁剪相关变量
        self.is_cropping = False
        self.crop_start_point = QPoint()
        self.crop_end_point = QPoint()

        # 初始化裁剪区域
        self.crop_rect = None

        # 显示窗口
        self.show()

    def create_menu_bar(self):
        # 创建菜单栏
        menubar = self.menuBar()

        # 文件菜单
        file_menu = menubar.addMenu('文件')

        # 文件菜单动作
        load_image_action = QAction('加载图像', self)
        load_video_action = QAction('加载视频', self)
        save_image_action = QAction('保存图像', self)
        exit_action = QAction('退出', self)

        # 添加动作到文件菜单
        file_menu.addAction(load_image_action)
        file_menu.addAction(load_video_action)
        file_menu.addSeparator()
        file_menu.addAction(save_image_action)
        file_menu.addSeparator()
        file_menu.addAction(exit_action)

        # 编辑菜单
        edit_menu = menubar.addMenu('编辑')

        # 编辑菜单动作
        undo_action = QAction('撤销', self)
        redo_action = QAction('重做', self)
        copy_action = QAction('复制', self)
        paste_action = QAction('粘贴', self)

        # 添加动作到编辑菜单
        edit_menu.addAction(undo_action)
        edit_menu.addAction(redo_action)
        edit_menu.addSeparator()
        edit_menu.addAction(copy_action)
        edit_menu.addAction(paste_action)

        # 视图菜单
        view_menu = menubar.addMenu('视图')

        # 视图菜单动作
        zoom_in_action = QAction('放大', self)
        zoom_out_action = QAction('缩小', self)
        fit_to_screen_action = QAction('适应屏幕', self)

        # 添加动作到视图菜单
        view_menu.addAction(zoom_in_action)
        view_menu.addAction(zoom_out_action)
        view_menu.addAction(fit_to_screen_action)

        # 帮助菜单
        help_menu = menubar.addMenu('帮助')

        # 帮助菜单动作
        about_action = QAction('关于', self)
        help_action = QAction('帮助', self)

        # 添加动作到帮助菜单
        help_menu.addAction(help_action)
        help_menu.addSeparator()
        help_menu.addAction(about_action)

        # 连接动作信号与槽
        load_image_action.triggered.connect(self.load_image)
        load_video_action.triggered.connect(self.load_video)
        save_image_action.triggered.connect(self.save_image)
        exit_action.triggered.connect(self.close)

        undo_action.triggered.connect(self.undo)
        redo_action.triggered.connect(self.redo)
        copy_action.triggered.connect(self.copy)
        paste_action.triggered.connect(self.paste)

        zoom_in_action.triggered.connect(self.zoom_in)
        zoom_out_action.triggered.connect(self.zoom_out)
        fit_to_screen_action.triggered.connect(self.fit_to_screen)

        about_action.triggered.connect(self.about)
        help_action.triggered.connect(self.show_help)

    def create_tool_bar(self):
        # 创建工具栏
        toolbar = self.addToolBar('工具栏')

        # 添加工具按钮
        load_image_btn = QAction('加载图像', self)
        load_video_btn = QAction('加载视频', self)
        save_image_btn = QAction('保存图像', self)
        undo_btn = QAction('撤销', self)
        redo_btn = QAction('重做', self)
        zoom_in_btn = QAction('放大', self)
        zoom_out_btn = QAction('缩小', self)
        fit_to_screen_btn = QAction('适应屏幕', self)

        # 添加按钮到工具栏
        toolbar.addAction(load_image_btn)
        toolbar.addAction(load_video_btn)
        toolbar.addAction(save_image_btn)
        toolbar.addSeparator()
        toolbar.addAction(undo_btn)
        toolbar.addAction(redo_btn)
        toolbar.addSeparator()
        toolbar.addAction(zoom_in_btn)
        toolbar.addAction(zoom_out_btn)
        toolbar.addAction(fit_to_screen_btn)

        # 连接按钮信号与槽
        load_image_btn.triggered.connect(self.load_image)
        load_video_btn.triggered.connect(self.load_video)
        save_image_btn.triggered.connect(self.save_image)
        undo_btn.triggered.connect(self.undo)
        redo_btn.triggered.connect(self.redo)
        zoom_in_btn.triggered.connect(self.zoom_in)
        zoom_out_btn.triggered.connect(self.zoom_out)
        fit_to_screen_btn.triggered.connect(self.fit_to_screen)

    def connect_signals(self):
        # 图像加载与显示信号
        self.load_image_btn.clicked.connect(self.load_image)
        self.save_image_btn.clicked.connect(self.save_image)
        self.reset_image_btn.clicked.connect(self.reset_image)
        self.zoom_in_btn.clicked.connect(self.zoom_in)
        self.zoom_out_btn.clicked.connect(self.zoom_out)
        self.fit_to_screen_btn.clicked.connect(self.fit_to_screen)

        # 图像编辑信号
        self.rotate_btn.clicked.connect(self.rotate_image)
        self.scale_btn.clicked.connect(self.scale_image)
        self.start_crop_btn.clicked.connect(self.start_crop)
        self.apply_crop_btn.clicked.connect(self.apply_crop)

        # 图像色彩调整信号
        self.brightness_slider.valueChanged.connect(self.update_brightness_label)
        self.contrast_slider.valueChanged.connect(self.update_contrast_label)
        self.saturation_slider.valueChanged.connect(self.update_saturation_label)
        self.apply_color_btn.clicked.connect(self.apply_color_adjustment)

        # 图像平滑处理信号
        self.apply_smoothing_btn.clicked.connect(self.apply_smoothing)

        # 形状识别信号
        self.detect_shapes_btn.clicked.connect(self.detect_shapes)

        # 图像拼接信号
        self.add_image_for_stitch_btn.clicked.connect(self.add_image_for_stitch)
        self.stitch_images_btn.clicked.connect(self.stitch_images)

        # 人脸识别信号
        self.detect_faces_btn.clicked.connect(self.detect_faces)
        # self.recognize_faces_btn.clicked.connect(self.recognize_faces)
        # self.register_face_btn.clicked.connect(self.register_face)

        # 视频处理信号
        self.load_video_btn.clicked.connect(self.load_video)
        self.play_video_btn.clicked.connect(self.play_video)
        self.pause_video_btn.clicked.connect(self.pause_video)
        self.stop_video_btn.clicked.connect(self.stop_video)
        self.next_frame_btn.clicked.connect(self.next_frame)
        self.prev_frame_btn.clicked.connect(self.prev_frame)
        self.start_webcam_btn.clicked.connect(self.start_webcam)
        self.stop_webcam_btn.clicked.connect(self.stop_webcam)
        self.apply_cv_to_webcam_btn.clicked.connect(self.apply_cv_to_webcam)

    # 图像加载与显示功能
    def load_image(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择图像文件", "", "图像文件 (*.png *.jpg *.jpeg *.bmp *.gif)"
        )

        if file_path:
            self.image = cv2.imread(file_path)
            self.original_image = self.image.copy()
            self.processed_image = self.image.copy()
            self.display_image()
            self.statusBar().showMessage(f"已加载图像: {os.path.basename(file_path)}")
            self.results_area.append(f"已加载图像: {os.path.basename(file_path)}")

    def save_image(self):
        if self.image is not None:
            file_path, _ = QFileDialog.getSaveFileName(
                self, "保存图像文件", "", "图像文件 (*.png *.jpg *.jpeg *.bmp)"
            )

            if file_path:
                cv2.imwrite(file_path, self.image)
                self.statusBar().showMessage(f"已保存图像: {os.path.basename(file_path)}")
                self.results_area.append(f"已保存图像: {os.path.basename(file_path)}")

    def reset_image(self):
        if self.original_image is not None:
            self.image = self.original_image.copy()
            self.processed_image = self.image.copy()
            self.display_image()
            self.statusBar().showMessage("图像已重置")
            self.results_area.append("图像已重置")

    def zoom_in(self):
        if self.image is not None:
            self.display_area.setScaledContents(False)
            current_size = self.display_area.pixmap().size()
            new_size = current_size * 1.2
            self.display_area.resize(new_size)

    def zoom_out(self):
        if self.image is not None:
            self.display_area.setScaledContents(False)
            current_size = self.display_area.pixmap().size()
            new_size = current_size * 0.8
            self.display_area.resize(new_size)

    def fit_to_screen(self):
        if self.image is not None:
            self.display_area.setScaledContents(True)

    # 图像编辑功能
    def rotate_image(self):
        if self.image is not None:
            angle = self.rotation_angle_spin.value()
            height, width = self.image.shape[:2]
            center = (width // 2, height // 2)

            rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
            self.image = cv2.warpAffine(self.image, rotation_matrix, (width, height))
            self.processed_image = self.image.copy()
            self.display_image()
            self.statusBar().showMessage(f"图像已旋转 {angle} 度")
            self.results_area.append(f"图像已旋转 {angle} 度")

    def scale_image(self):
        if self.image is not None:
            scale_factor = self.scale_factor_spin.value()
            self.image = cv2.resize(self.image, None, fx=scale_factor, fy=scale_factor)
            self.processed_image = self.image.copy()
            self.display_image()
            self.statusBar().showMessage(f"图像已按比例 {scale_factor} 缩放")
            self.results_area.append(f"图像已按比例 {scale_factor} 缩放")

    def start_crop(self):
        if self.image is not None:
            self.is_cropping = True
            self.crop_start_point = QPoint()
            self.crop_end_point = QPoint()
            self.display_area.setMouseTracking(True)
            self.display_area.mousePressEvent = self.mouse_press_event
            self.display_area.mouseMoveEvent = self.mouse_move_event
            self.display_area.mouseReleaseEvent = self.mouse_release_event
            self.apply_crop_btn.setEnabled(False)
            self.statusBar().showMessage("请在图像上拖动鼠标选择裁剪区域")
            self.results_area.append("请在图像上拖动鼠标选择裁剪区域")

    def mouse_press_event(self, event):
        if self.is_cropping and event.button() == Qt.LeftButton:
            self.crop_start_point = event.pos()

    def mouse_move_event(self, event):
        if self.is_cropping and event.buttons() & Qt.LeftButton:
            self.crop_end_point = event.pos()
            self.display_image()

    def mouse_release_event(self, event):
        if self.is_cropping and event.button() == Qt.LeftButton:
            self.crop_end_point = event.pos()
            self.apply_crop_btn.setEnabled(True)
            self.statusBar().showMessage("裁剪区域已选择，点击'应用裁剪'按钮确认")
            self.results_area.append("裁剪区域已选择，点击'应用裁剪'按钮确认")

    def apply_crop(self):
        if self.is_cropping and self.crop_start_point != QPoint() and self.crop_end_point != QPoint():
            # 确保起点和终点坐标正确排序
            x1 = min(self.crop_start_point.x(), self.crop_end_point.x())
            y1 = min(self.crop_start_point.y(), self.crop_end_point.y())
            x2 = max(self.crop_start_point.x(), self.crop_end_point.x())
            y2 = max(self.crop_start_point.y(), self.crop_end_point.y())

            # 转换为图像坐标
            pixmap = self.display_area.pixmap()
            if pixmap:
                image_width = pixmap.width()
                image_height = pixmap.height()
                original_width = self.image.shape[1]
                original_height = self.image.shape[0]

                scale_x = original_width / image_width
                scale_y = original_height / image_height

                x1 = int(x1 * scale_x)
                y1 = int(y1 * scale_y)
                x2 = int(x2 * scale_x)
                y2 = int(y2 * scale_y)

                # 确保坐标在有效范围内
                x1 = max(0, min(x1, original_width - 1))
                y1 = max(0, min(y1, original_height - 1))
                x2 = max(0, min(x2, original_width - 1))
                y2 = max(0, min(y2, original_height - 1))

                # 裁剪图像
                if x2 > x1 and y2 > y1:
                    self.image = self.image[y1:y2, x1:x2]
                    self.processed_image = self.image.copy()
                    self.display_image()
                    self.statusBar().showMessage("图像已裁剪")
                    self.results_area.append("图像已裁剪")
                else:
                    self.statusBar().showMessage("无效的裁剪区域")
                    self.results_area.append("无效的裁剪区域")

            self.is_cropping = False
            self.apply_crop_btn.setEnabled(False)

    # 图像色彩调整功能
    def update_brightness_label(self):
        value = self.brightness_slider.value()
        self.brightness_value_label.setText(f"亮度: {value}")

    def update_contrast_label(self):
        value = self.contrast_slider.value()
        self.contrast_value_label.setText(f"对比度: {value}")

    def update_saturation_label(self):
        value = self.saturation_slider.value()
        self.saturation_value_label.setText(f"饱和度: {value}")

    def apply_color_adjustment(self):
        if self.image is not None:
            brightness = self.brightness_slider.value()
            contrast = self.contrast_slider.value()
            saturation = self.saturation_slider.value()

            # 调整亮度和对比度
            if brightness != 0 or contrast != 0:
                # 转换为浮点数进行计算
                img_float = np.float32(self.image)

                # 调整对比度
                if contrast != 0:
                    factor = 259 / (255 * (259 - contrast))
                    img_float = factor * (img_float - 128) + 128

                # 调整亮度
                img_float = np.clip(img_float + brightness, 0, 255)

                # 转回uint8类型
                self.image = np.uint8(img_float)

            # 调整饱和度
            if saturation != 0 and len(self.image.shape) == 3:
                # 转换为HSV色彩空间
                hsv = cv2.cvtColor(self.image, cv2.COLOR_BGR2HSV)

                # 分离通道
                h, s, v = cv2.split(hsv)

                # 调整饱和度
                if saturation > 0:
                    limit = 255 - saturation
                    s = np.minimum(s + saturation, limit)
                else:
                    s = np.maximum(s + saturation, 0)

                # 合并通道并转回BGR色彩空间
                hsv = cv2.merge([h, s, v])
                self.image = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

            self.processed_image = self.image.copy()
            self.display_image()
            self.statusBar().showMessage("色彩调整已应用")
            self.results_area.append(f"色彩调整已应用: 亮度={brightness}, 对比度={contrast}, 饱和度={saturation}")

    # 图像平滑处理功能
    def apply_smoothing(self):
        if self.image is not None:
            algorithm = self.smoothing_algorithm_combo.currentText()
            kernel_size = self.kernel_size_spin.value()

            if algorithm == "均值滤波":
                self.image = cv2.blur(self.image, (kernel_size, kernel_size))
            elif algorithm == "高斯滤波":
                self.image = cv2.GaussianBlur(self.image, (kernel_size, kernel_size), 0)
            elif algorithm == "中值滤波":
                self.image = cv2.medianBlur(self.image, kernel_size)
            elif algorithm == "双边滤波":
                # 双边滤波需要不同的参数
                self.image = cv2.bilateralFilter(self.image, 9, 75, 75)

            self.processed_image = self.image.copy()
            self.display_image()
            self.statusBar().showMessage(f"已应用{algorithm}")
            self.results_area.append(f"已应用{algorithm}，内核大小={kernel_size}")

    # 形状识别功能
    def detect_shapes(self):
        if self.image is not None:
            shape_type = self.shape_type_combo.currentText()

            # 复制原始图像用于处理
            img_gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
            img_blur = cv2.GaussianBlur(img_gray, (5, 5), 0)
            img_canny = cv2.Canny(img_blur, 50, 150)

            # 查找轮廓
            contours, _ = cv2.findContours(img_canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

            # 结果图像
            result = self.image.copy()

            detected_shapes = []

            # 检测每种形状
            for contour in contours:
                epsilon = 0.04 * cv2.arcLength(contour, True)
                approx = cv2.approxPolyDP(contour, epsilon, True)
                area = cv2.contourArea(contour)

                # 忽略过小的轮廓
                if area < 100:
                    continue

                shape = "未识别"

                if shape_type == "所有形状" or shape_type == "圆形":
                    # 圆形检测
                    (x, y), radius = cv2.minEnclosingCircle(contour)
                    circle_area = np.pi * radius * radius

                    if abs(area - circle_area) / circle_area < 0.2:
                        shape = "圆形"
                        if shape_type == "所有形状" or shape_type == "圆形":
                            cv2.circle(result, (int(x), int(y)), int(radius),
                                       (self.shape_color.blue(), self.shape_color.green(), self.shape_color.red()), 2)
                            detected_shapes.append(f"圆形: 中心=({int(x)}, {int(y)}), 半径={int(radius)}")

                if shape == "未识别" and (shape_type == "所有形状" or shape_type == "矩形"):
                    # 矩形检测
                    if len(approx) == 4:
                        shape = "矩形"
                        if shape_type == "所有形状" or shape_type == "矩形":
                            cv2.drawContours(result, [approx], 0,
                                             (self.shape_color.blue(), self.shape_color.green(), self.shape_color.red()), 2)
                            detected_shapes.append(f"矩形: 顶点数={len(approx)}")

                if shape == "未识别" and (shape_type == "所有形状" or shape_type == "三角形"):
                    # 三角形检测
                    if len(approx) == 3:
                        shape = "三角形"
                        if shape_type == "所有形状" or shape_type == "三角形":
                            cv2.drawContours(result, [approx], 0,
                                             (self.shape_color.blue(), self.shape_color.green(), self.shape_color.red()), 2)
                            detected_shapes.append(f"三角形: 顶点数={len(approx)}")

                if shape == "未识别" and (shape_type == "所有形状" or shape_type == "多边形"):
                    # 多边形检测
                    if len(approx) > 4:
                        shape = "多边形"
                        if shape_type == "所有形状" or shape_type == "多边形":
                            cv2.drawContours(result, [approx], 0,
                                             (self.shape_color.blue(), self.shape_color.green(), self.shape_color.red()), 2)
                            detected_shapes.append(f"多边形: 顶点数={len(approx)}")

            self.image = result
            self.processed_image = self.image.copy()
            self.display_image()

            if detected_shapes:
                self.statusBar().showMessage(f"已检测到 {len(detected_shapes)} 个形状")
                self.results_area.append(f"已检测到 {len(detected_shapes)} 个形状:")
                for s in detected_shapes:
                    self.results_area.append(f"- {s}")
            else:
                self.statusBar().showMessage("未检测到任何形状")
                self.results_area.append("未检测到任何形状")

    # 图像拼接功能
    def add_image_for_stitch(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择图像文件", "", "图像文件 (*.png *.jpg *.jpeg *.bmp *.gif)"
        )

        if file_path:
            img = cv2.imread(file_path)
            self.stitch_images_list.append(img)
            self.stitch_images_display.setText(f"已添加图像: {len(self.stitch_images_list)}")
            self.statusBar().showMessage(f"已添加图像用于拼接: {os.path.basename(file_path)}")
            self.results_area.append(f"已添加图像用于拼接: {os.path.basename(file_path)}")

    def stitch_images(self):
        if len(self.stitch_images_list) < 2:
            QMessageBox.warning(self, "警告", "至少需要添加两张图像才能进行拼接")
            return

        # 创建拼接器
        stitcher = cv2.Stitcher_create()

        # 拼接图像
        status, result = stitcher.stitch(self.stitch_images_list)

        if status == cv2.Stitcher_OK:
            self.image = result
            self.original_image = self.image.copy()
            self.processed_image = self.image.copy()
            self.display_image()
            self.statusBar().showMessage("图像拼接成功")
            self.results_area.append("图像拼接成功")

            # 清空拼接图像列表
            self.stitch_images_list = []
            self.stitch_images_display.setText(f"已添加图像: {len(self.stitch_images_list)}")
        else:
            error_messages = {
                cv2.Stitcher_ERR_NEED_MORE_IMGS: "需要更多图像才能进行拼接",
                cv2.Stitcher_ERR_HOMOGRAPHY_EST_FAIL: "单应性矩阵估计失败",
                cv2.Stitcher_ERR_CAMERA_PARAMS_ADJUST_FAIL: "相机参数调整失败"
            }
            error_msg = error_messages.get(status, "图像拼接失败，未知错误")
            self.statusBar().showMessage(error_msg)
            self.results_area.append(f"图像拼接失败: {error_msg}")

    # 人脸识别功能（使用OpenCV替代）
    def detect_faces(self):
        if self.image is not None:
            # 转换为灰度图
            gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)

            # 检测人脸
            faces = face_cascade.detectMultiScale(
                gray,
                scaleFactor=1.1,
                minNeighbors=5,
                minSize=(30, 30),
                flags=cv2.CASCADE_SCALE_IMAGE
            )

            # 在原图上绘制人脸框
            result = self.image.copy()

            for (x, y, w, h) in faces:
                cv2.rectangle(result, (x, y), (x+w, y+h), (0, 255, 0), 2)

            self.image = result
            self.processed_image = self.image.copy()
            self.display_image()

            if len(faces) > 0:
                self.statusBar().showMessage(f"已检测到 {len(faces)} 个人脸")
                self.results_area.append(f"已检测到 {len(faces)} 个人脸")
            else:
                self.statusBar().showMessage("未检测到人脸")
                self.results_area.append("未检测到人脸")

    # 视频处理功能
    def load_video(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择视频文件", "", "视频文件 (*.mp4 *.avi *.mov *.mkv)"
        )

        if file_path:
            self.video_capture = cv2.VideoCapture(file_path)
            self.is_video_playing = False
            self.update_frame()
            self.statusBar().showMessage(f"已加载视频: {os.path.basename(file_path)}")
            self.results_area.append(f"已加载视频: {os.path.basename(file_path)}")

    def play_video(self):
        if self.video_capture and not self.is_video_playing:
            self.is_video_playing = True
            self.timer.start(30)  # 约30fps
            self.statusBar().showMessage("视频播放中")
            self.results_area.append("视频播放中")

    def pause_video(self):
        if self.is_video_playing:
            self.is_video_playing = False
            self.timer.stop()
            self.statusBar().showMessage("视频已暂停")
            self.results_area.append("视频已暂停")

    def stop_video(self):
        if self.video_capture:
            self.is_video_playing = False
            self.timer.stop()
            self.video_capture.set(cv2.CAP_PROP_POS_FRAMES, 0)  # 重置到第一帧
            self.update_frame()
            self.statusBar().showMessage("视频已停止")
            self.results_area.append("视频已停止")

    def next_frame(self):
        if self.video_capture:
            current_frame = self.video_capture.get(cv2.CAP_PROP_POS_FRAMES)
            if current_frame < self.video_capture.get(cv2.CAP_PROP_FRAME_COUNT) - 1:
                self.video_capture.set(cv2.CAP_PROP_POS_FRAMES, current_frame + 1)
                self.update_frame()

    def prev_frame(self):
        if self.video_capture:
            current_frame = self.video_capture.get(cv2.CAP_PROP_POS_FRAMES)
            if current_frame > 0:
                self.video_capture.set(cv2.CAP_PROP_POS_FRAMES, current_frame - 1)
                self.update_frame()

    def update_frame(self):
        if self.video_capture:
            ret, frame = self.video_capture.read()

            if ret:
                self.image = frame
                self.processed_image = self.image.copy()
                self.display_image()

                # 更新进度条
                total_frames = self.video_capture.get(cv2.CAP_PROP_FRAME_COUNT)
                current_frame = self.video_capture.get(cv2.CAP_PROP_POS_FRAMES)
                progress = int((current_frame / total_frames) * 100)
                self.video_progress.setValue(progress)
            else:
                # 视频结束
                self.is_video_playing = False
                self.timer.stop()
                self.statusBar().showMessage("视频播放完毕")
                self.results_area.append("视频播放完毕")

    def start_webcam(self):
        self.video_capture = cv2.VideoCapture(0)
        self.is_video_playing = True
        self.timer.start(30)  # 约30fps
        self.statusBar().showMessage("摄像头已启动")
        self.results_area.append("摄像头已启动")

    def stop_webcam(self):
        if self.video_capture:
            self.is_video_playing = False
            self.timer.stop()
            self.video_capture.release()
            self.display_area.setText("请加载图像或视频")
            self.statusBar().showMessage("摄像头已停止")
            self.results_area.append("摄像头已停止")

    def apply_cv_to_webcam(self):
        if self.video_capture and self.is_video_playing:
            # 在实时视频上应用计算机视觉算法
            current_tab = self.processing_tabs.currentIndex()

            if current_tab == 6:  # 人脸识别
                self.apply_face_detection_to_video()
            elif current_tab == 4:  # 形状识别
                self.apply_shape_detection_to_video()
            else:
                QMessageBox.information(self, "提示", "当前仅支持在实时视频上应用人脸检测和形状识别功能")

    def apply_face_detection_to_video(self):
        if self.video_capture and self.is_video_playing:
            # 转换为灰度图
            gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)

            # 检测人脸
            faces = face_cascade.detectMultiScale(
                gray,
                scaleFactor=1.1,
                minNeighbors=5,
                minSize=(30, 30),
                flags=cv2.CASCADE_SCALE_IMAGE
            )

            # 在原图上绘制人脸框
            result = self.image.copy()

            for (x, y, w, h) in faces:
                cv2.rectangle(result, (x, y), (x+w, y+h), (0, 255, 0), 2)

            self.image = result
            self.processed_image = self.image.copy()
            self.display_image()

    def apply_shape_detection_to_video(self):
        if self.video_capture and self.is_video_playing:
            # 复制原始图像用于处理
            img_gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
            img_blur = cv2.GaussianBlur(img_gray, (5, 5), 0)
            img_canny = cv2.Canny(img_blur, 50, 150)

            # 查找轮廓
            contours, _ = cv2.findContours(img_canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

            # 结果图像
            result = self.image.copy()

            # 检测每种形状
            for contour in contours:
                epsilon = 0.04 * cv2.arcLength(contour, True)
                approx = cv2.approxPolyDP(contour, epsilon, True)
                area = cv2.contourArea(contour)

                # 忽略过小的轮廓
                if area < 100:
                    continue

                # 圆形检测
                (x, y), radius = cv2.minEnclosingCircle(contour)
                circle_area = np.pi * radius * radius

                if abs(area - circle_area) / circle_area < 0.2:
                    cv2.circle(result, (int(x), int(y)), int(radius),
                               (self.shape_color.blue(), self.shape_color.green(), self.shape_color.red()), 2)
                    continue

                # 矩形检测
                if len(approx) == 4:
                    cv2.drawContours(result, [approx], 0,
                                     (self.shape_color.blue(), self.shape_color.green(), self.shape_color.red()), 2)
                    continue

                # 三角形检测
                if len(approx) == 3:
                    cv2.drawContours(result, [approx], 0,
                                     (self.shape_color.blue(), self.shape_color.green(), self.shape_color.red()), 2)
                    continue

                # 多边形检测
                if len(approx) > 4:
                    cv2.drawContours(result, [approx], 0,
                                     (self.shape_color.blue(), self.shape_color.green(), self.shape_color.red()), 2)

            self.image = result
            self.processed_image = self.image.copy()
            self.display_image()

    # 辅助函数
    def display_image(self):
        if self.image is not None:
            # 转换为RGB格式
            rgb_image = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)

            # 如果正在裁剪，显示裁剪框
            if self.is_cropping and self.crop_start_point != QPoint() and self.crop_end_point != QPoint():
                height, width = rgb_image.shape[:2]
                img_qt = QImage(rgb_image.data, width, height, QImage.Format_RGB888)

                # 创建一个可绘制的QPixmap
                pixmap = QPixmap.fromImage(img_qt)
                painter = QPainter(pixmap)
                painter.setPen(QPen(Qt.red, 2, Qt.DashLine))

                # 绘制裁剪框
                painter.drawRect(QRect(self.crop_start_point, self.crop_end_point))
                painter.end()

                self.display_area.setPixmap(pixmap)
            else:
                # 直接显示图像
                height, width = rgb_image.shape[:2]
                bytes_per_line = 3 * width
                q_img = QImage(rgb_image.data, width, height, bytes_per_line, QImage.Format_RGB888)
                self.display_area.setPixmap(QPixmap.fromImage(q_img))

    # 编辑菜单功能
    def undo(self):
        pass  # 实现撤销功能

    def redo(self):
        pass  # 实现重做功能

    def copy(self):
        pass  # 实现复制功能

    def paste(self):
        pass  # 实现粘贴功能

    # 帮助菜单功能
    def about(self):
        QMessageBox.about(self, "关于", "计算机视觉开发平台\n\n版本: 1.0\n\n本平台实现了基础图像处理、人脸检测和视频处理等功能。")

    def show_help(self):
        help_text = """
        计算机视觉开发平台使用帮助

        1. 图像加载与显示
           - 点击"加载图像"按钮选择本地图像文件
           - 使用缩放按钮调整图像显示大小

        2. 图像处理
           - 图像编辑: 旋转、缩放和裁剪图像
           - 色彩调整: 调整亮度、对比度和饱和度
           - 平滑处理: 应用多种滤波算法减少图像噪声
           - 形状识别: 检测图像中的圆形、矩形、三角形和多边形
           - 图像拼接: 将多张图像拼接成全景图

        3. 人脸检测
           - 检测图像或视频中的人脸

        4. 视频处理
           - 加载和播放本地视频文件
           - 控制视频播放(播放、暂停、停止等)
           - 启动摄像头并进行实时视频处理

        更多详细信息请参考文档。
        """
        QMessageBox.information(self, "帮助", help_text)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = CVPlatform()
    sys.exit(app.exec_())